﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MiniExcelLibs;
using Sunny.UI;
using CtyDataCollection.Models;
using CtyDataCollection.Helper;
using System.Threading;
using ScottPlot;
using ScottPlot.Plottable;
using System.Diagnostics;



namespace CtyDataCollection
{
    public partial class FormMain : UIForm
    {
        private DataGetModel _selectedGetModel;//选中的excel数据
        private List<DataGetModel> dataGetModels;
        private S7Helper s7Helper;

        double[] liveData = new double[400];//存储实时更新的动态数据
        DataGen.Electrocardiogram ecg = new DataGen.Electrocardiogram();//用于生成模拟的心电图数据
        Stopwatch sw = Stopwatch.StartNew();//测量时间间隔，以便后续根据时间生成数据
        VLine vline;

        private CancellationTokenSource _ctsWrite = new CancellationTokenSource();
        private CancellationTokenSource _ctsDataCopy = new CancellationTokenSource();
        private CancellationTokenSource _ctsPlotRefresh = new CancellationTokenSource();

        private Task _taskWrite;
        private Task _taskDataCopy;
        private Task _taskPlotRefresh;

        private bool _acqEnable = false;
        int nextValueIndex = 0;
        public FormMain()
        {
            
            InitializeComponent();
            InitExcelData();//初始化excel数据
            CycleReadTempData();//循环读取plc温度数据
            InitPlot(); //初始化图表坐标数据数据

        }

        #region 初始化excel数据
        public void InitExcelData()
        {
            try
            {
                //读取配置文件
                var iniFilePath = AppDomain.CurrentDomain.BaseDirectory + "config.ini";
                IniFile ini = new IniFile(iniFilePath);
                string dataGetPath = ini.ReadString("Setup", "DataGetPath", "DataGet.xlsx");
                string dataSetPath = ini.ReadString("Setup", "DataSetPath", "DataSet.xlsx");

                //读取excel
                using (var stream = File.OpenRead(AppDomain.CurrentDomain.BaseDirectory + dataGetPath))
                {
                    dataGetModels = stream.Query<DataGetModel>().ToList();
                    gridPlc.DataSource = dataGetModels;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

        }
        #endregion

        #region 循环读取温度
        public void CycleReadTempData()
        {
            Thread thread = new Thread(() =>
            {
                while (true)
                {
                    try
                    {
                        if (s7Helper != null && s7Helper.Connected)
                        {
                            var tempture = s7Helper.ReadSingleData_Float(1, 4, 4, PlcDataType.Float);
                            Invoke(new Action(() =>
                            {
                                uiTempture.Value = tempture;
                            }));
                        }
                        Thread.Sleep(500);

                    }
                    catch (Exception ex)
                    {

                        HLog.Error("读取温度失败", ex);
                    }
                }
            });
            thread.Start();
        }
        #endregion

        #region 初始化图表坐标数据数据
        public void InitPlot()
        {
            //传入初始化数据，后续会加入更新的数据
            formsPlot1.Plot.AddSignal(liveData);
            //设置 X 轴自动缩放，并且设置边距为 0
            formsPlot1.Plot.AxisAutoX(margin: 0);
            //设置 Y 轴的范围，最小值为 -1，最大值为 2.5
            formsPlot1.Plot.SetAxisLimits(yMin: -1, yMax: 200);

            //绘制一条红色垂直线并保存，以便稍后移动
            vline = formsPlot1.Plot.AddVerticalLine(0, Color.Red, 2);

            //自定义样式
            formsPlot1.Plot.Title("温度图");
            formsPlot1.Plot.YLabel("温度");
            formsPlot1.Plot.XLabel("时间(seconds)");
            formsPlot1.Plot.Grid(false);

            formsPlot1.Refresh();
        }
        #endregion

        #region 更新图表数据
        private async Task UpdateDataTask(CancellationToken ct)
        {
            while (_acqEnable && !_ctsDataCopy.IsCancellationRequested)
            {
                // 从 plc 里面读取
                double nextValue = 0;

                if (s7Helper != null && s7Helper.Connected)
                {
                    if (_selectedGetModel != null)
                    {
                        nextValue = s7Helper.ReadSingleData_Float(1, _selectedGetModel.Address.ToInt(), 4, PlcDataType.Float);
                    }
                    //nextValue = s7Helper.ReadSingleData_Float(1, 4, 4, PlcDataType.Float);

                }

                if (uiCheckBoxRoll.Checked)
                {
                    // "roll" new values over old values like a traditional ECG machine
                    nextValueIndex = (nextValueIndex < liveData.Length - 1) ? nextValueIndex + 1 : 0;
                    liveData[nextValueIndex] = nextValue;
                    vline.IsVisible = true;
                    vline.X = nextValueIndex;
                }
                else
                {
                    // "scroll" the whole chart to the left
                    Array.Copy(liveData, 1, liveData, 0, liveData.Length - 1);
                    liveData[liveData.Length - 1] = nextValue;
                    vline.IsVisible = false;
                }
                if (formsPlot1.IsHandleCreated)
                {
                    formsPlot1.BeginInvoke(new Action(() =>
                    {
                        formsPlot1.Plot.Clear();
                        formsPlot1.Plot.AddSignal(liveData);
                        formsPlot1.Refresh();
                    }));
                }

                await Task.Delay(100, ct);
            }
        }
        #endregion

        #region 刷新图表
        private async Task PlotRefreshTask(CancellationToken ct)
        {
            while (!_ctsPlotRefresh.IsCancellationRequested)
            {
                Invoke(new Action(() =>
                {
                    formsPlot1.Refresh();
                }));

                await Task.Delay(100, ct);
            }
        }
        #endregion

        #region 向plc写入数据
        private async Task MockDataTask(CancellationToken ct)
        {
            while (!ct.IsCancellationRequested)
            {
                var nextValue = (float)ecg.GetVoltage(sw.Elapsed.TotalSeconds);

                //模拟数据
                if (s7Helper != null && s7Helper.Connected)
                {
                    if (_selectedGetModel != null)
                    {
                        s7Helper.WriteSingleData_Float(1,
                            _selectedGetModel.Address.ToInt(),
                            nextValue,
                            4
                            , PlcDataType.Float);

                    }
                }
                await Task.Delay(100, ct);
            }
        }
        #endregion

        #region plc连接开关状态变化
        private void uiTurnSwitch1_ValueChanged(object sender, bool value)
        {
            if (uiTurnSwitch1.Active)
            {
                try
                {
                    s7Helper = new S7Helper("S71200", s7Ip.Text);
                    var status = s7Helper.ConnectPLC(s7Port.Value, (short)s7Rack.Value, (short)s7Slot.Value);

                    //改变plc指示灯状态
                    s7Status.State = status ? UILightState.On : UILightState.Off;
                    //读取温度数据
                    /*
                     1 代表DB1
                     4 代表偏移量
                     4 float占4个字节
                    DB1.DBD4 float
                     */
                    var temputre = s7Helper.ReadSingleData_Float(1, 4, 4, PlcDataType.Float);
                    uiTempture.Value = temputre;
                }
                catch (Exception ex)
                {

                    Console.WriteLine(ex.Message);
                }
            }
        }
        #endregion

        #region excel选中行变化
        private void gridPlc_SelectIndexChange(object sender, int index)
        {
            if (gridPlc.SelectedRows.Count > 0)
            {
                //映射选中excel行的数据为实体对象存储
                _selectedGetModel = gridPlc.SelectedRows[0].DataBoundItem as DataGetModel;

                if (_selectedGetModel == null)
                {
                    MessageBox.Show("转换失败");
                }
            }
        }
        #endregion

        #region 点击模拟数据
        private void uiButtonMock_Click(object sender, EventArgs e)
        {
            _ctsWrite?.Cancel();
            _ctsWrite = new CancellationTokenSource();
            _taskWrite = Task.Run(() => MockDataTask(_ctsWrite.Token), _ctsWrite.Token);
        }
        #endregion

        #region 点击采集数据
        private void uiButtonAcq_Click(object sender, EventArgs e)
        {
            if (_acqEnable)
            {
                sw.Stop();
                _acqEnable = false;
                _ctsDataCopy?.Cancel();
                _ctsPlotRefresh?.Cancel();
            }
            else
            {
                sw.Start();
                _acqEnable = true;
                _ctsDataCopy = new CancellationTokenSource();
                _ctsPlotRefresh = new CancellationTokenSource();
                //启动异步任务更新图表数据
                _taskDataCopy = Task.Run(() => UpdateDataTask(_ctsDataCopy.Token), _ctsDataCopy.Token);
                //启动异步任务刷新图表
                _taskPlotRefresh = Task.Run(() => PlotRefreshTask(_ctsPlotRefresh.Token), _ctsPlotRefresh.Token);
            }
        }
        #endregion

        #region 当切换心电图显示方式时，清空旧数据
        private void uiCheckBoxRoll_CheckedChanged(object sender, EventArgs e)
        {
            for (int i = 0; i < liveData.Length; i++)
                liveData[i] = 0;
        }
        #endregion
    }
}
